package com.hllxd.hism.star.basic.service.service;

import com.alibaba.fastjson.JSON;
import com.hllxd.hism.star.basic.service.dao.mapper.mis.PermissionInfoMapper;
import com.hllxd.hism.star.basic.service.dao.mapper.mis.RoleInfoMapper;
import com.hllxd.hism.star.basic.service.model.AllUserPermission;
import com.hllxd.hism.star.basic.service.model.PermissionInfo;
import com.hllxd.hism.star.basic.service.model.RoleInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.*;

/**
 * @author fangpeiyun
 */
@Slf4j
@Service("roleService")
public class RoleServiceImpl implements RoleService {


    /** 需要鉴权的uri集合 */
    private static final String ALL_PERMISSION_KEY = "star_permission_all_set";
    /** 用户前缀标识 */
    public static final String KEY_PREFIX = "star_permission_all_user_";

    private static final String DEVELOPER = "lixiyong01";

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private RoleInfoMapper roleInfoMapper;

    @Autowired
    private PermissionInfoMapper permissionInfoMapper;


    @Override
    public List<RoleInfo> listRole(String search) {
        if(StringUtils.isNotEmpty(search)) {
            return roleInfoMapper.listRole("%"+search+"%" );
        }
        return roleInfoMapper.listRole(null);
    }

    @Override
    public List<RoleInfo> listRoleByLabel(String functionLabel) {
        log.info("functionLabel: {}", functionLabel);
        return roleInfoMapper.listRoleByTag(null,null, functionLabel);
    }

    @Override
    public List<RoleInfo> listRoleByUserGroupId(String userId, Long userGroupId) {
        return roleInfoMapper.listRoleByTag(userId, userGroupId, null);
    }

    @Override
    public Long delPermissionRole(Long id) {
        return roleInfoMapper.updateRoleInfoAction(id);
    }

    @Override
    public long setRoleInfo(RoleInfo roleInfo) {
        log.info("set param: {}", JSON.toJSONString(roleInfo));
        if (roleInfo.id == null || roleInfo.id == 0) {
            return roleInfoMapper.insertRoleInfo(roleInfo);
        } else {
            return roleInfoMapper.updateRoleInfo(roleInfo);
        }
    }

    @Override
    public RoleInfo getRoleInfo(Long id) {
        log.info("getRoleInfo: {}.", id);
        return roleInfoMapper.getOneRoleInfo(id);
    }


    @Override
    public long delRoleInfo(Long id) {
        RoleInfo roleInfo = roleInfoMapper.getOneRoleInfo(id);
//        if(! handlePermissionCache(roleInfo.userIds, roleInfo.userGroupIds)) {
//            log.warn("handle permission failed.");
//        }
        return roleInfoMapper.updateRoleInfoAction(id);
    }

    @Override
    public long updateRoleUserGroupIdCache(Long userGroupId, String originUgUserName, String updateUgUserName) {
        if (originUgUserName.equals(updateUgUserName)) {
            return 0;
        }

        ArrayList<String> toAdd = new ArrayList<>();
        ArrayList<String> toDel = new ArrayList<>();

        List<String> origin = Arrays.asList(originUgUserName.split(","));
        List<String> update = Arrays.asList(updateUgUserName.split(","));

        origin.forEach(x -> {
            if (!update.contains(x)) {
                toDel.add(x);
            }
        });

        update.forEach(x -> {
            if (!origin.contains(x)) {
                toAdd.add(x);
            }
        });

        return toAdd.size() + toDel.size();
    }

    @Override
    public Long delRoleRoleUserGroupIdMysql(Long userGroupId) {
        long l = 0L;
        List<RoleInfo> roleInfoList = roleInfoMapper.getRoleInfoByUserGroupId(userGroupId);
        for (RoleInfo roleInfo : roleInfoList) {
            String[] split = roleInfo.getUserGroupIds().split(",");
            StringBuilder sb = new StringBuilder();
            for (String s : split) {
                if (!s.equals(userGroupId.toString())) {
                    sb.append(s).append(",");
                }
            }
            if (sb.length() >= 2) {
                sb.deleteCharAt(sb.length() - 1);
            }
            roleInfo.setUserGroupIds(sb.toString());
            l += roleInfoMapper.updateRoleInfo(roleInfo);
        }

        return l;
    }

    @Override
    public String refreshPermission() {
        try {
            if (! executeBuildCache()) {
                return "FAILURE";
            }
        }catch (Exception e) {
            return "FAILURE";
        }
        return "SUCCESS";
    }

    /** 下线uri需要将所有的用户释放权限, 在删除uri的时候触发 */
    public boolean executeUriBuildCache(String uri) throws Exception {
        delUriPermissionKey(uri);
        return true;
    }

//    /** 处理缓冲 */
//    public boolean handlePermissionCache(String userIds, String userGroupIds) {
//        // 获取所有的用户
//        StringBuilder sb = new StringBuilder();
//        List<AllUserPermission> allUser = permissionInfoMapper.getAllUser(userIds, userGroupIds);
//        for (AllUserPermission user : allUser) {
//            redisTemplate.delete(KEY_PREFIX + user.getUserName());
//
//            if(sb.length()>1) {
//                sb.append(',');
//            }
//            sb.append(user.getUserName());
//        }
//        // 获取用户以及权限
//        List<AllUserPermission> allUserPermission = permissionInfoMapper.getUserPermission(sb.toString());
//        for (AllUserPermission userPermission : allUserPermission) {
//            String pUserName = userPermission.getUserName();
//            if (pUserName != null) {
//                setUserPermission(pUserName, userPermission.getFunctionLabel(), userPermission.getFunctionItem());
//            }
//        }
//        return true;
//    }


    @PostConstruct
    public boolean executeBuildCache() throws Exception {

        log.warn("init start permission cache build ...");
        // 清理所有的权限URI
        List<PermissionInfo> allPermission = permissionInfoMapper.getAllPermission();
        redisTemplate.delete(ALL_PERMISSION_KEY);
        // 清理所有用户的权限缓存
        Set<String> userKeys = redisTemplate.keys(KEY_PREFIX + "*");
        if (userKeys != null) {
            for (String userKey : userKeys) {
                redisTemplate.delete(userKey);
            }
        }
        // 设置所有用户的缓存
        List<AllUserPermission> allUserPermission = permissionInfoMapper.getAllUserPermission();
        for (AllUserPermission userPermission : allUserPermission) {
            String pUserName = userPermission.getUserName();
            if (pUserName != null) {
                setUserPermission(pUserName, userPermission.getFunctionLabel(), userPermission.getFunctionItem());
            }
        }
        // 设置权限URI
        for (PermissionInfo permissionInfo : allPermission) {
            String functionItem = permissionInfo.getFunctionItem();
            Integer permissionType = permissionInfo.getPermissionType();
            if (permissionType == 0) {
                setUriPermissionKey(functionItem);
            }
        }
        log.warn("init end permission cache build.");

        return true;
    }

    private void setUriPermissionKey(String uri) {
        redisTemplate.opsForSet().add(ALL_PERMISSION_KEY, uri);
    }
    private void delUriPermissionKey(String uri) {
        redisTemplate.opsForSet().remove(ALL_PERMISSION_KEY, uri);
    }
    private void setUserPermission(String userName, String label, String uri) {
        redisTemplate.opsForHash().put(KEY_PREFIX + userName, label, uri);
    }

    @Override
    public Boolean validate(String userName, String permissionUri) {

        String permissionUrl = permissionUri.replaceAll("/+", "/");
        Boolean needCheck = redisTemplate.opsForSet().isMember(ALL_PERMISSION_KEY, permissionUrl);
        log.info("url: {}, need check: {}.",permissionUrl, needCheck);
        boolean hasConfigPermission = Boolean.TRUE.equals(needCheck);
        if (hasConfigPermission) {
            log.info("check user permission, user: {}, uri: {}", userName, permissionUrl);
            Map<Object, Object> entries = redisTemplate.opsForHash().entries(KEY_PREFIX + userName);
            Collection<Object> values = entries.values();
            if (values.contains(permissionUrl)) {
                log.info("has power.");
                return true;
            } else {
                log.info("no power.");
                return false;
            }
        }
        // 排除开发者
        if (DEVELOPER.equals(userName)) {
            log.info("use developer power.");
            return true;
        }
        return true;
    }
}
